package com.stars.easyms.logging.boot;

import com.stars.easyms.base.util.ApplicationContextHolder;
import com.stars.easyms.base.util.ReflectUtil;
import com.stars.easyms.logging.interceptor.EasyMsLoggingAnnotationAsyncExecutionInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.aop.Advice;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.scheduling.annotation.AnnotationAsyncExecutionInterceptor;
import org.springframework.scheduling.annotation.AsyncAnnotationAdvisor;
import org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * <p>className: EasyMsLoggingRunner</p>
 * <p>description: EasyMsLoggingRunner</p>
 *
 * @author guoguifang
 * @version 1.7.1
 * @date 2020/12/19 10:26 上午
 */
@Slf4j
public class EasyMsLoggingBeanPostProcessor implements BeanPostProcessor, Ordered {

    private static final AtomicBoolean INIT = new AtomicBoolean(false);

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        AsyncAnnotationBeanPostProcessor processor = ApplicationContextHolder.getBean(AsyncAnnotationBeanPostProcessor.class);
        if (processor != null && INIT.compareAndSet(false, true)) {
            Object processorAdvisorObj = ReflectUtil.readFieldWithoutException(processor, "advisor");
            if (processorAdvisorObj instanceof AsyncAnnotationAdvisor) {
                AsyncAnnotationAdvisor asyncAnnotationAdvisor = (AsyncAnnotationAdvisor) processorAdvisorObj;
                Advice advice = asyncAnnotationAdvisor.getAdvice();
                if (advice instanceof AnnotationAsyncExecutionInterceptor) {
                    EasyMsLoggingAnnotationAsyncExecutionInterceptor interceptor = new EasyMsLoggingAnnotationAsyncExecutionInterceptor();
                    try {
                        ReflectUtil.writeFinalField(interceptor,
                                "logger", ReflectUtil.readFieldWithoutException(advice, "logger"));
                        ReflectUtil.writeFinalField(interceptor,
                                "executors", ReflectUtil.readFieldWithoutException(advice, "executors"));
                        ReflectUtil.writeField(interceptor,
                                "defaultExecutor", ReflectUtil.readFieldWithoutException(advice, "defaultExecutor"));
                        ReflectUtil.writeField(interceptor,
                                "exceptionHandler", ReflectUtil.readFieldWithoutException(advice, "exceptionHandler"));
                        ReflectUtil.writeField(interceptor,
                                "beanFactory", ReflectUtil.readFieldWithoutException(advice, "beanFactory"));
                        ReflectUtil.writeField(asyncAnnotationAdvisor, "advice", interceptor);
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                    }
                }
            }
        }
        return bean;
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}
